﻿/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * High-Resolution Timer Class
 *      Provides a high-resolution timer class.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Timers;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Runtime.InteropServices;
using Adaptive.Win32;

namespace Adaptive.Foundation
{
    /// <summary>
    /// Provides a high-resolution timer class.
    /// </summary>
    [DefaultProperty("Interval"), DefaultEvent("Elapsed"),
     HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
    public class HighResolutionTimer : Component, ISupportInitialize
    {
        /*--------------------------------------------------------------------------------
         * Public Event Definitions
         *------------------------------------------------------------------------------*/
        #region Public Event Definitions
        /// <summary>
        /// Occurs when the timer interval elapses.
        /// </summary>
        [TimersDescription("TimerIntervalElapsed"), Category("Behavior")]
        public event EventHandler Elapsed;
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Constants Declarations
         *------------------------------------------------------------------------------*/
        #region Private Constants Declarations
        /// <summary>
        /// Default interval value.
        /// </summary>
        private const float DEFAULT_INTERVAL = 0.5f;
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------*/
        #region Private Member Declarations
        /// <summary>
        /// Interval to wait, in seconds.
        /// </summary>
        private float _interval = DEFAULT_INTERVAL;
        /// <summary>
        /// Auto-reset flag.
        /// </summary>
        private bool _autoReset;
        /// <summary>
        /// Enabled flag.
        /// </summary>
        private bool _enabled;
        /// <summary>
        /// Initialization flag.
        /// </summary>
        private bool _initializing;
        /// <summary>
        /// Disposal flag.
        /// </summary>
        private bool _disposed;
        private bool _delayedEnable;
        /// <summary>
        /// Internal Timer instance.
        /// </summary>
        private InternalTimer _timer;
        /// <summary>
        /// Synchronization object.
        /// </summary>
        private object _cookie;
        /// <summary>
        /// Synchronization object.
        /// </summary>
        private ISynchronizeInvoke _synchronizingObject;
        #endregion

        /*--------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        public HighResolutionTimer()
            : base()
        {
            _interval = DEFAULT_INTERVAL;
            _enabled = false;
            _autoReset = true;
            _initializing = false;
            _delayedEnable = false;

        }
        /// <summary>
        /// Initializes a new instance of the class to the specified interval.
        /// </summary>
        /// <param name="interval">
        /// The number of seconds to wait.
        /// </param>
        public HighResolutionTimer(float interval)
        {
            _interval = interval;
            _enabled = false;
            _autoReset = true;
            _initializing = false;
            _delayedEnable = false;
        }
        /// <summary>
        /// Deallocates internally allocated objects.
        /// </summary>
        /// <param name="disposing">
        /// A value indicating whether the object is being disposed.
        /// </param>
        protected override void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                Close();
                _disposed = true;
            }
            base.Dispose(disposing);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets or sets a value indicating whether the <b>Timer</b> should raise the <b>Elapsed</b> event each time the 
        /// specified interval elapses or only after the first time it elapses.
        /// </summary>
        /// <value>
        /// <b>true</b> if the <see cref="System.Timers.Timer"/> should raise the <see cref="Elapsed"/> event each time the interval 
        /// elapses; <b>false</b> if it should raise the <see cref="Elapsed"/> event only once, after the first time the 
        /// interval elapses. The default is <b>true</b>.
        /// </value>
        public bool AutoReset
        {
            get
            {
                return _autoReset;
            }
            set
            {
                if (base.DesignMode)
                {
                    _autoReset = value;
                }
                else if (_autoReset != value)
                {
                    _autoReset = value;
                }
            }
        }
        /// <summary>
        /// Gets or sets a value indicating whether the <see cref="HighResolutionTimer"/> should raise the <see cref="Elapsed"/> event.
        /// </summary>
        /// <value>
        /// <b>true</b> if the <see cref="HighResolutionTimer"/> should raise the 
        /// <see cref="Elapsed"/> event; otherwise, <b>false</b>. The default is <b>false</b>.
        /// </value>
        [DefaultValue(false), Category("Behavior"), TimersDescription("TimerEnabled")]
        public bool Enabled
        {
            get
            {
                return _enabled;
            }
            set
            {
                if (base.DesignMode)
                {
                    _delayedEnable = value;
                    _enabled = value;
                }
                else if (_initializing)
                {
                    _delayedEnable = value;
                }
                else if (_enabled != value)
                {
                    if (!value)
                    {
                        if (_timer != null)
                        {
                            _cookie = null;
                            _timer.Stop();
                            _timer.Elapsed -= new EventHandler(HandleInternalElapsed);
                            _timer.Dispose();
                            _timer = null;
                        }
                        _enabled = value;
                    }
                    else
                    {
                        _enabled = value;
                        if (_timer == null)
                        {
                            if (_disposed)
                            {
                                throw new ObjectDisposedException(base.GetType().Name);
                            }
                            int dueTime = (int)Math.Ceiling(_interval);
                            _cookie = new object();
                            _timer = new InternalTimer(_interval);
                            _timer.AutoReset = _autoReset;
                            _timer.Elapsed += new EventHandler(HandleInternalElapsed);
                            _timer.Start();
                        }
                        else
                        {
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Gets or sets the interval at which to raise the <see cref="Elapsed"/> event.
        /// </summary>
        /// <value>
        /// The time, in milliseconds, between raisings of the <see cref="Elapsed"/> event. The default is 0.5 seconds.
        /// </value>
        /// <exception cref="ArgumentException">The interval is less than or equal to zero. </exception>
        [SettingsBindable(true), DefaultValue((float)0.5), Category("Behavior"), TimersDescription("TimerInterval")]
        public float Interval
        {
            get
            {
                return _interval;
            }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentException("Invalid timer interval specified.");
                }
                _interval = value;
                if (_timer != null)
                    _timer.Interval = value;
            }
        }
        /// <summary>
        /// Gets or sets the site that binds the <see cref="HighResolutionTimer"/> to its container in design mode.
        /// </summary>
        /// <value>
        /// An <see cref="ISite"/> interface representing the site that binds the <see cref="HighResolutionTimer"/> object to its container
        /// </value>
        public override ISite Site
        {
            get
            {
                return base.Site;
            }
            set
            {
                base.Site = value;
                if (base.DesignMode)
                {
                    _enabled = true;
                }
            }
        }
        /// <summary>
        /// Gets or sets the object used to marshal event-handler calls that are issued when an interval has elapsed.
        /// </summary>
        /// <value>
        /// The <see cref="ISynchronizeInvoke"/> representing the object used to marshal the event-handler calls that are 
        /// issued when an interval has elapsed. The default is null.
        /// </value>
        [TimersDescription("TimerSynchronizingObject"), Browsable(false), DefaultValue((string)null)]
        public ISynchronizeInvoke SynchronizingObject
        {
            get
            {
                if ((_synchronizingObject == null) && base.DesignMode)
                {
                    IDesignerHost service = (IDesignerHost)base.GetService(typeof(IDesignerHost));
                    if (service != null)
                    {
                        object rootComponent = service.RootComponent;
                        if ((rootComponent != null) && (rootComponent is ISynchronizeInvoke))
                        {
                            _synchronizingObject = (ISynchronizeInvoke)rootComponent;
                        }
                    }
                }
                return _synchronizingObject;
            }
            set
            {
                _synchronizingObject = value;
            }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Protected Methods / Event Methods
         *------------------------------------------------------------------------------*/
        #region Protected Methods / Event Methods
        /// <summary>
        /// Raises the <see cref="Elapsed"/> event.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnElapsed(EventArgs e)
        {
            try
            {
                if (Elapsed != null)
                {
                    if ((SynchronizingObject != null) && SynchronizingObject.InvokeRequired)
                    {
                        SynchronizingObject.BeginInvoke(Elapsed, new object[] { this, e });
                    }
                    else
                    {
                        Elapsed(this, e);
                    }
                }
            }
            catch
            {
            }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Public Methods / Functions
        /// <summary>
        /// Begins the run-time initialization of a Timer that is used on a form or by another component.
        /// </summary>
        public void BeginInit()
        {
            Close();
            _initializing = true;
        }
        /// <summary>
        /// Clears the contents of the object instance without disposing of the instance.
        /// </summary>
        public void Close()
        {
            _initializing = false;
            _delayedEnable = false;
            _enabled = false;
            if (_timer != null)
            {
                _timer.Stop();
                _timer.Dispose();
                _timer = null;
            }
        }
        /// <summary>
        /// Ends the run-time initialization of a Timer that is used on a form or by another component.
        /// </summary>
        public void EndInit()
        {
            _initializing = false;
            Enabled = _delayedEnable;
        }
        /// <summary>
        /// Begins execution of the timer.
        /// </summary>
        public void Start()
        {
            Enabled = true;
        }
        /// <summary>
        /// Stops execution of the timer.
        /// </summary>
        public void Stop()
        {
            Enabled = false;
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Event Handlers
         *------------------------------------------------------------------------------*/
        #region Private Event Handlers
        private void HandleInternalElapsed(object sender, EventArgs e)
        {
            OnElapsed(e);
        }
        #endregion


    }
}
